// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// IP地址操作
// 
// IPv4地址为4字节；IPv6地址为16字节。
// 可以通过添加规范前缀（10个零，2个0xFFs）将IPv4地址转换为IPv6地址。
// 此库接受任意大小的字节片，但始终返回16字节地址。

package net

import (
	"internal/bytealg"
	"internal/itoa"
)

// IP地址长度（字节）。
const (
	IPv4len = 4
	IPv6len = 16
)

// IP是单个IP地址，一个字节片。
// 此包中的函数接受4字节（IPv4）
// 或16字节（IPv6）片作为输入。
// 
// 注意，在本文档中，将
// IP地址称为IPv4地址或IPv6地址
// 是地址的语义属性，而不仅仅是字节片的
// 长度：16字节片仍然可以是IPv4地址。
type IP []byte

// IPMask是一种位掩码，可用于操纵IP寻址和路由的IP地址。
// 
// 有关详细信息，请参见IPNet和func ParseCIDR类型。
type IPMask []byte

// 一个IPNet代表一个IP网络。
type IPNet struct {
	IP   IP     // 网络号
	Mask IPMask // 网络掩码
}

// IPv4返回
// IPv4地址a.b.c.d.
func IPv4(a, b, c, d byte) IP {
	p := make(IP, IPv6len)
	copy(p, v4InV6Prefix)
	p[12] = a
	p[13] = b
	p[14] = c
	p[15] = d
	return p
}

var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}

// IPv4Mask返回IP掩码（4字节格式）
// IPv4掩码a.b.c.d.
func IPv4Mask(a, b, c, d byte) IPMask {
	p := make(IPMask, IPv4len)
	p[0] = a
	p[1] = b
	p[2] = c
	p[3] = d
	return p
}

// CIDRMask返回一个IPMask，该IPMask由“一”个1位
// 后跟0，总长度为“位”。
// 对于这种形式的掩码，CIDRMask是IPMask.Size的倒数。
func CIDRMask(ones, bits int) IPMask {
	if bits != 8*IPv4len && bits != 8*IPv6len {
		return nil
	}
	if ones < 0 || ones > bits {
		return nil
	}
	l := bits / 8
	m := make(IPMask, l)
	n := uint(ones)
	for i := 0; i < l; i++ {
		if n >= 8 {
			m[i] = 0xff
			n -= 8
			continue
		}
		m[i] = ^byte(0xff >> n)
		n = 0
	}
	return m
}

// 众所周知的IPv4地址
var (
	IPv4bcast     = IPv4(255, 255, 255, 255) // 有限广播
	IPv4allsys    = IPv4(224, 0, 0, 1)       // 所有系统
	IPv4allrouter = IPv4(224, 0, 0, 2)       // 所有路由器
	IPv4zero      = IPv4(0, 0, 0, 0)         // 全零
)

// 众所周知的IPv6地址
var (
	IPv6zero                   = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	IPv6unspecified            = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	IPv6loopback               = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
	IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
	IPv6linklocalallnodes      = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
	IPv6linklocalallrouters    = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
)

// 未指定报告ip是否为未指定地址，
// IPv4地址“0.0.0.0”或IPv6地址：“。
func (ip IP) IsUnspecified() bool {
	return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified)
}

// IsLoopback报告ip是否为环回地址。
func (ip IP) IsLoopback() bool {
	if ip4 := ip.To4(); ip4 != nil {
		return ip4[0] == 127
	}
	return ip.Equal(IPv6loopback)
}

// IsPrivate根据
// RFC 1918（IPv4地址）和RFC 4193（IPv6地址）报告ip是否为私有地址。
func (ip IP) IsPrivate() bool {
	if ip4 := ip.To4(); ip4 != nil {
		// 遵循RFC 1918第3节。私有地址空间，上面写着：
		// 互联网分配号码管理局（IANA）已经为私有互联网保留了以下三块IP地址空间：
		// 10.0.0-10.255.255.255（10/8前缀）
		return ip4[0] == 10 ||
			(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
			(ip4[0] == 192 && ip4[1] == 168)
	}
	// IANA已将FC00:：/7前缀指定给“唯一本地单播”。
	return len(ip) == IPv6len && ip[0]&0xfe == 0xfc
}

// IsMulticast报告ip是否为多播地址。
func (ip IP) IsMulticast() bool {
	if ip4 := ip.To4(); ip4 != nil {
		return ip4[0]&0xf0 == 0xe0
	}
	return len(ip) == IPv6len && ip[0] == 0xff
}

// IsInterfaceLocalMulticast报告ip是否为
// 接口本地多播地址。
func (ip IP) IsInterfaceLocalMulticast() bool {
	return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
}

// IsLinkLocalMulticast报告ip是否为本地链路
// 多播地址。
func (ip IP) IsLinkLocalMulticast() bool {
	if ip4 := ip.To4(); ip4 != nil {
		return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0
	}
	return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x02
}

// IsLinkLocalUnicast报告ip是否为本地链路
// 单播地址。
func (ip IP) IsLinkLocalUnicast() bool {
	if ip4 := ip.To4(); ip4 != nil {
		return ip4[0] == 169 && ip4[1] == 254
	}
	return len(ip) == IPv6len && ip[0] == 0xfe && ip[1]&0xc0 == 0x80
}

// IsGlobalUnicast报告ip是否为全局单播
// 地址。
// 
// 全局单播地址的标识使用地址类型
// 在RFC 1122、RFC 4632和RFC 4291中定义的带有
// 的标识，IPv4定向广播地址除外。
// 即使ip位于IPv4专用地址空间或
// 本地IPv6单播地址空间中，也返回true。
func (ip IP) IsGlobalUnicast() bool {
	return (len(ip) == IPv4len || len(ip) == IPv6len) &&
		!ip.Equal(IPv4bcast) &&
		!ip.IsUnspecified() &&
		!ip.IsLoopback() &&
		!ip.IsMulticast() &&
		!ip.IsLinkLocalUnicast()
}

// p都是零吗？
func isZeros(p IP) bool {
	for i := 0; i < len(p); i++ {
		if p[i] != 0 {
			return false
		}
	}
	return true
}

// To4将IPv4地址ip转换为4字节表示形式。
// 如果ip不是IPv4地址，To4返回零。
func (ip IP) To4() IP {
	if len(ip) == IPv4len {
		return ip
	}
	if len(ip) == IPv6len &&
		isZeros(ip[0:10]) &&
		ip[10] == 0xff &&
		ip[11] == 0xff {
		return ip[12:16]
	}
	return nil
}

// To16将IP地址IP转换为16字节的表示形式。
// 如果ip不是ip地址（长度错误），To16返回零。
func (ip IP) To16() IP {
	if len(ip) == IPv4len {
		return IPv4(ip[0], ip[1], ip[2], ip[3])
	}
	if len(ip) == IPv6len {
		return ip
	}
	return nil
}

// IPv4的默认路由掩码。
var (
	classAMask = IPv4Mask(0xff, 0, 0, 0)
	classBMask = IPv4Mask(0xff, 0xff, 0, 0)
	classCMask = IPv4Mask(0xff, 0xff, 0xff, 0)
)

// DefaultMask返回IP地址IP的默认IP掩码。
// 只有IPv4地址有默认掩码；如果ip不是有效的IPv4地址，DefaultMask返回
// nil。
func (ip IP) DefaultMask() IPMask {
	if ip = ip.To4(); ip == nil {
		return nil
	}
	switch {
	case ip[0] < 0x80:
		return classAMask
	case ip[0] < 0xC0:
		return classBMask
	default:
		return classCMask
	}
}

func allFF(b []byte) bool {
	for _, c := range b {
		if c != 0xff {
			return false
		}
	}
	return true
}

// Mask返回使用掩码屏蔽IP地址的结果。
func (ip IP) Mask(mask IPMask) IP {
	if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
		mask = mask[12:]
	}
	if len(mask) == IPv4len && len(ip) == IPv6len && bytealg.Equal(ip[:12], v4InV6Prefix) {
		ip = ip[12:]
	}
	n := len(ip)
	if n != len(mask) {
		return nil
	}
	out := make(IP, n)
	for i := 0; i < n; i++ {
		out[i] = ip[i] & mask[i]
	}
	return out
}

// ubtoa将整数v的字符串形式编码为dst[start:]和
// 返回写入dst的字节数。调用方必须确保
// dst具有足够的长度。
func ubtoa(dst []byte, start int, v byte) int {
	if v < 10 {
		dst[start] = v + '0'
		return 1
	} else if v < 100 {
		dst[start+1] = v%10 + '0'
		dst[start] = v/10 + '0'
		return 2
	}

	dst[start+2] = v%10 + '0'
	dst[start+1] = (v/10)%10 + '0'
	dst[start] = v/100 + '0'
	return 3
}

// String返回IP地址IP的字符串形式。
// 返回四种形式之一：
// /-“<nil>”，如果ip的长度为0 
// /-点十进制（“192.0.2.1”），如果ip是IPv4或IP4映射的IPv6地址
// /-IPv6（“2001:db8:：1”），如果ip是有效的IPv6地址
// /-ip的十六进制形式，没有标点符号，如果没有其他情况适用
func (ip IP) String() string {
	p := ip

	if len(ip) == 0 {
		return "<nil>"
	}

	// 如果是IPv4，请使用点符号。
	if p4 := p.To4(); len(p4) == IPv4len {
		const maxIPv4StringLen = len("255.255.255.255")
		b := make([]byte, maxIPv4StringLen)

		n := ubtoa(b, 0, p4[0])
		b[n] = '.'
		n++

		n += ubtoa(b, n, p4[1])
		b[n] = '.'
		n++

		n += ubtoa(b, n, p4[2])
		b[n] = '.'
		n++

		n += ubtoa(b, n, p4[3])
		return string(b[:n])
	}
	if len(p) != IPv6len {
		return "?" + hexString(ip)
	}

	// 查找零的最长行程。
	e0 := -1
	e1 := -1
	for i := 0; i < IPv6len; i += 2 {
		j := i
		for j < IPv6len && p[j] == 0 && p[j+1] == 0 {
			j += 2
		}
		if j > i && j-i > e1-e0 {
			e0 = i
			e1 = j
			i = j
		}
	}
	// 符号“：”不能仅用于缩短一个16位0字段。
	if e1-e0 <= 2 {
		e0 = -1
		e1 = -1
	}

	const maxLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
	b := make([]byte, 0, maxLen)

	// 打印时可能使用：：代替零的运行
	for i := 0; i < IPv6len; i += 2 {
		if i == e0 {
			b = append(b, ':', ':')
			i = e1
			if i >= IPv6len {
				break
			}
		} else if i > 0 {
			b = append(b, ':')
		}
		b = appendHex(b, (uint32(p[i])<<8)|uint32(p[i+1]))
	}
	return string(b)
}

func hexString(b []byte) string {
	s := make([]byte, len(b)*2)
	for i, tn := range b {
		s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
	}
	return string(s)
}

// ipEmptyString与ip.String类似，只是在ip未设置时返回一个空字符串。
func ipEmptyString(ip IP) string {
	if len(ip) == 0 {
		return ""
	}
	return ip.String()
}

// MarshalText实现了encoding.TextMarshaler接口。
// 编码与字符串返回的编码相同，只有一个例外：
// 当len（ip）为零时，返回一个空切片。
func (ip IP) MarshalText() ([]byte, error) {
	if len(ip) == 0 {
		return []byte(""), nil
	}
	if len(ip) != IPv4len && len(ip) != IPv6len {
		return nil, &AddrError{Err: "invalid IP address", Addr: hexString(ip)}
	}
	return []byte(ip.String()), nil
}

// UnmarshalText实现encoding.TextUnmarshaler接口。
// IP地址应为ParseIP接受的格式。
func (ip *IP) UnmarshalText(text []byte) error {
	if len(text) == 0 {
		*ip = nil
		return nil
	}
	s := string(text)
	x := ParseIP(s)
	if x == nil {
		return &ParseError{Type: "IP address", Text: s}
	}
	*ip = x
	return nil
}

// Equal报告ip和x是否为相同的ip地址。
// IPv4地址和IPv6形式的相同地址视为相等。
func (ip IP) Equal(x IP) bool {
	if len(ip) == len(x) {
		return bytealg.Equal(ip, x)
	}
	if len(ip) == IPv4len && len(x) == IPv6len {
		return bytealg.Equal(x[0:12], v4InV6Prefix) && bytealg.Equal(ip, x[12:])
	}
	if len(ip) == IPv6len && len(x) == IPv4len {
		return bytealg.Equal(ip[0:12], v4InV6Prefix) && bytealg.Equal(ip[12:], x)
	}
	return false
}

func (ip IP) matchAddrFamily(x IP) bool {
	return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil
}

// 如果掩码是一个1位加0位的序列，
// 返回1位的数字。
func simpleMaskLength(mask IPMask) int {
	var n int
	for i, v := range mask {
		if v == 0xff {
			n += 8
			continue
		}
		// 找到的非ff字节
		// 计数1位
		for v&0x80 != 0 {
			n++
			v <<= 1
		}
		// 其余必须为0位
		if v != 0 {
			return -1
		}
		for i++; i < len(mask); i++ {
			if mask[i] != 0 {
				return -1
			}
		}
		break
	}
	return n
}

// Size返回掩码中的前导字节数和总位数。
// 如果掩码不是标准形式（1后跟0），则
// Size返回0，0。
func (m IPMask) Size() (ones, bits int) {
	ones, bits = simpleMaskLength(m), len(m)*8
	if ones == -1 {
		return 0, 0
	}
	return
}

// 字符串返回m的十六进制形式，不带标点符号。
func (m IPMask) String() string {
	if len(m) == 0 {
		return "<nil>"
	}
	return hexString(m)
}

func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
	if ip = n.IP.To4(); ip == nil {
		ip = n.IP
		if len(ip) != IPv6len {
			return nil, nil
		}
	}
	m = n.Mask
	switch len(m) {
	case IPv4len:
		if len(ip) != IPv4len {
			return nil, nil
		}
	case IPv6len:
		if len(ip) == IPv4len {
			m = m[12:]
		}
	default:
		return nil, nil
	}
	return
}

// 包含网络是否包含ip的报告。
func (n *IPNet) Contains(ip IP) bool {
	nn, m := networkNumberAndMask(n)
	if x := ip.To4(); x != nil {
		ip = x
	}
	l := len(ip)
	if l != len(nn) {
		return false
	}
	for i := 0; i < l; i++ {
		if nn[i]&m[i] != ip[i]&m[i] {
			return false
		}
	}
	return true
}

// 网络返回地址的网络名称“ip+net”。
func (n *IPNet) Network() string { return "ip+net" }

// 字符串返回n的CIDR表示法，如RFC 4632和RFC 4291中定义的“192.0.2.0/24”
// 或“2001:db8:：/48”。
// 如果掩码不是标准格式，则返回由IP地址组成的
// 字符串，后跟斜杠
// 字符和表示为十六进制格式的掩码，不带
// 标点，如“198.51.100.0/c000ff00”。
func (n *IPNet) String() string {
	nn, m := networkNumberAndMask(n)
	if nn == nil || m == nil {
		return "<nil>"
	}
	l := simpleMaskLength(m)
	if l == -1 {
		return nn.String() + "/" + m.String()
	}
	return nn.String() + "/" + itoa.Uitoa(uint(l))
}

// 解析IPv4地址（d.d.d.d）。
func parseIPv4(s string) IP {
	var p [IPv4len]byte
	for i := 0; i < IPv4len; i++ {
		if len(s) == 0 {
			// 缺少八位字节。
			return nil
		}
		if i > 0 {
			if s[0] != '.' {
				return nil
			}
			s = s[1:]
		}
		n, c, ok := dtoi(s)
		if !ok || n > 0xFF {
			return nil
		}
		if c > 1 && s[0] == '0' {
			// 拒绝带前导零的非零组件。
			return nil
		}
		s = s[c:]
		p[i] = byte(n)
	}
	if len(s) != 0 {
		return nil
	}
	return IPv4(p[0], p[1], p[2], p[3])
}

// parseIPv6Zone解析为文本IPv6地址及其关联区域
// 标识符，如RFC 4007所述。
func parseIPv6Zone(s string) (IP, string) {
	s, zone := splitHostZone(s)
	return parseIPv6(s), zone
}

// 解析IPv6解析为RFC 4291 
// 和RFC 5952中描述的文本IPv6地址。
func parseIPv6(s string) (ip IP) {
	ip = make(IP, IPv6len)
	ellipsis := -1 // 省略号在ip中的位置

	// 可能有前导省略号
	if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
		ellipsis = 0
		s = s[2:]
		// 可能只是省略号
		if len(s) == 0 {
			return ip
		}
	}

	// 循环，解析后跟冒号的十六进制数。
	i := 0
	for i < IPv6len {
		// 十六进制数。
		n, c, ok := xtoi(s)
		if !ok || n > 0xFFFF {
			return nil
		}

		// 如果后跟点，则可能位于IPv4的尾部。
		if c < len(s) && s[c] == '.' {
			if ellipsis < 0 && i != IPv6len-IPv4len {
				// 位置不对。
				return nil
			}
			if i+IPv4len > IPv6len {
				// 空间不够。
				return nil
			}
			ip4 := parseIPv4(s)
			if ip4 == nil {
				return nil
			}
			ip[i] = ip4[12]
			ip[i+1] = ip4[13]
			ip[i+2] = ip4[14]
			ip[i+3] = ip4[15]
			s = ""
			i += IPv4len
			break
		}

		// 保存此16位块。
		ip[i] = byte(n >> 8)
		ip[i+1] = byte(n)
		i += 2

		// 在字符串末尾停止。
		s = s[c:]
		if len(s) == 0 {
			break
		}

		// 否则必须后跟冒号等。
		if s[0] != ':' || len(s) == 1 {
			return nil
		}
		s = s[1:]

		// 查找省略号。
		if s[0] == ':' {
			if ellipsis >= 0 { // 已经有一个
				return nil
			}
			ellipsis = i
			s = s[1:]
			if len(s) == 0 { // 可以在末尾
				break
			}
		}
	}

	// 必须使用整个字符串。
	if len(s) != 0 {
		return nil
	}

	// 如果解析不够，请展开省略号。
	if i < IPv6len {
		if ellipsis < 0 {
			return nil
		}
		n := IPv6len - i
		for j := i - 1; j >= ellipsis; j-- {
			ip[j+n] = ip[j]
		}
		for j := ellipsis + n - 1; j >= ellipsis; j-- {
			ip[j] = 0
		}
	} else if ellipsis >= 0 {
		// 省略号必须至少表示一个0组。
		return nil
	}
	return ip
}

// ParseIP解析为IP地址，返回结果。
// 字符串s可以是IPv4点十进制（“192.0.2.1”）、IPv6 
// /（“2001:db8:：68”）或IPv4映射IPv6（“：：ffff:192.0.2.1”）形式。
// 如果s不是IP地址的有效文本表示形式，
// ParseIP返回nil。
func ParseIP(s string) IP {
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '.':
			return parseIPv4(s)
		case ':':
			return parseIPv6(s)
		}
	}
	return nil
}

// parseIPZone解析为IP地址，返回它及其关联区域
// 标识符（仅限IPv6）。
func parseIPZone(s string) (IP, string) {
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '.':
			return parseIPv4(s), ""
		case ':':
			return parseIPv6Zone(s)
		}
	}
	return nil, ""
}

// ParseCIDR解析为CIDR符号IP地址和前缀长度，如
// RFC 4632和RFC 4291中定义的“192.0.2.0/24”或“2001:db8:：/32”。
// 
// 返回IP和
// 前缀长度所隐含的IP地址和网络。
// 例如，ParseCIDR（“192.0.2.1/24”）返回IP地址
// 192.0.2.1和网络192.0.2.0/24。
func ParseCIDR(s string) (IP, *IPNet, error) {
	i := bytealg.IndexByteString(s, '/')
	if i < 0 {
		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
	}
	addr, mask := s[:i], s[i+1:]
	iplen := IPv4len
	ip := parseIPv4(addr)
	if ip == nil {
		iplen = IPv6len
		ip = parseIPv6(addr)
	}
	n, i, ok := dtoi(mask)
	if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
	}
	m := CIDRMask(n, 8*iplen)
	return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
}
